/*
 * Main.java
 */

package xq.runner;

import com.marklogic.xcc.exceptions.ServerConnectionException;
import com.marklogic.xcc.exceptions.XQueryException;
import java.net.URI;
import java.util.Map;
import javax.swing.UIManager;
import xq.api.XQException;
import xq.api.XQRequest;
import xq.api.XQResponse;
import xq.api.XQService;
import xq.api.XQServiceFactory;
import xq.api.XQVariable;
import xq.api.XQuery;
import xq.session.SessionFactory;
import xq.util.ClasspathClassLoader;
import xq.util.XMLUtil;
import xq.util.ResourceUtil;
import xq.util.resource.TextResource;

import static xq.util.CommonUtil.empty;

/**
 *
 * @author ThorntonRP
 */
public class Main {

	public static void main(String[] args) throws Exception {
		xq.session.Session session = SessionFactory.getInstance().getSession();
		UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		Map<XQVariable, String> input = XQRunnerOptionPane.showOptionPane();
		if (input != null) {
			String connectionURI  = session.get(Session.CONNECTION_URI_KEY);
			String resourcePath   = session.get(Session.RESOURCE_PATH_KEY);
			String xqueryResource = session.get(Session.QUERY_RESOURCE_KEY);

			ClassLoader resourceLoader = new ClasspathClassLoader(resourcePath);
			TextResource queryResource = ResourceUtil.getTextResource(xqueryResource, resourceLoader);
			XQuery xquery = new XQuery(queryResource, resourceLoader);
			System.out.println("================================================================================");
			System.out.println("Query:");
			System.out.println("  " + xquery.getResourceAtLine(0).getResourceFile());
			System.out.println("Input:");
			System.out.print(formatInput(input));
			System.out.println("================================================================================");
			System.out.println("Result:");
			System.out.println("================================================================================");
			executeQuery(connectionURI, xquery, input);
		}
	}
	
	private static String formatInput(Map<XQVariable, String> input) {
		StringBuilder sb = new StringBuilder();
		int padWidth1 = 0;
		int padWidth2 = 0;
		for (Map.Entry<XQVariable, String> entry : input.entrySet()) {
			padWidth1 = Math.max(entry.getKey().getName().length(), padWidth1);
			padWidth2 = Math.max(entry.getKey().getType().length() + (entry.getKey().getMultiplicity() == null ? 0 : 1), padWidth2);
		}
		for (Map.Entry<XQVariable, String> entry : input.entrySet()) {
			sb.append("  ");
			sb.append("$");
			sb.append(entry.getKey().getName());
			for (int i = entry.getKey().getName().length(); i < padWidth1; i++) {
				sb.append(' ');
			}
			sb.append(" as ");
			sb.append(entry.getKey().getType());
			sb.append(entry.getKey().getMultiplicity() == null ? "" : entry.getKey().getMultiplicity().getValue());
			for (int i = entry.getKey().getType().length() + (entry.getKey().getMultiplicity() == null ? 0 : 1); i < padWidth2; i++) {
				sb.append(' ');
			}
			sb.append(" = \"");
			sb.append(entry.getValue().replace("\"", "&quot;"));
			sb.append("\"\n");
		}
		return sb.toString();
	}

	private static void executeQuery(String connectionURI, XQuery xquery, Map<XQVariable, String> input) throws Exception {
		XQRequest request = new XQRequest(xquery);
		for (Map.Entry<XQVariable, String> entry : input.entrySet()) {
			request.setVariableInput(entry.getKey().getName(), entry.getValue());
		}
		XQService xqs = XQServiceFactory.getService(new URI(connectionURI));
		try {
			XQResponse<String> response = xqs.queryToString(request);
			System.out.println(XMLUtil.formatXML(response.getResult()));
		} catch (XQException ex) {
			if (ex.getCause() instanceof XQueryException) {
				XQueryException xqe = (XQueryException) ex.getCause();
				if (!empty(xqe.getStack())) {
					int lineNumber = xqe.getStack()[0].getLineNumber() - 1;
					String line = xquery.getLocationString(lineNumber);
					System.err.println(line + ": " + xqe.getFormatString());
				} else {
					ex.printStackTrace();
				}
			} else if (ex.getCause() instanceof ServerConnectionException) {
				System.err.println("Failed to connect to the Mark Logic server.");
			} else {
				ex.printStackTrace();
			}
		}
	}
}
